package com.guducat.collegeWeb.service;

import com.guducat.collegeWeb.dto.response.FileUploadResultDTO;
import io.minio.*;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * 文件上传服务
 * 处理文件上传到MinIO对象存储
 */
@Slf4j
@Service
public class FileUploadService {

    private final MinioClient minioClient;

    @Value("${MINIO_BUCKET_NAME:college-web}")
    private String bucketName;

    @Value("${MINIO_ENDPOINT:https://lobechat-s3.laffey.cc:49917}")
    private String endpoint;

    // 允许的图片文件类型
    private static final List<String> ALLOWED_IMAGE_TYPES = Arrays.asList(
            "image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp", "image/bmp"
    );

    // 最大文件大小：5MB
    private static final long MAX_FILE_SIZE = 5 * 1024 * 1024;

    @Autowired
    public FileUploadService(MinioClient minioClient) {
        this.minioClient = minioClient;
    }

    /**
     * 上传图片文件
     * @param file 上传的文件
     * @return 文件上传结果
     * @throws Exception 上传异常
     */
    public FileUploadResultDTO uploadImage(MultipartFile file) throws Exception {
        // 验证文件
        validateFile(file);

        // 确保存储桶存在
        ensureBucketExists();

        // 生成唯一文件名
        String fileName = generateUniqueFileName(file.getOriginalFilename());

        // 构建对象名（包含路径）
        String objectName = "images/" + fileName;

        try (InputStream inputStream = file.getInputStream()) {
            // 上传文件到MinIO
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .stream(inputStream, file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build()
            );

            log.info("文件上传成功: {}", objectName);

            // 生成访问URL
            String fileUrl = generateFileUrl(objectName);

            // 构建返回结果
            return new FileUploadResultDTO(
                    fileUrl,
                    fileName,
                    file.getOriginalFilename(),
                    file.getSize(),
                    file.getContentType(),
                    file.getOriginalFilename(), // alt属性使用原始文件名
                    "" // href属性为空
            );

        } catch (Exception e) {
            log.error("文件上传失败: {}", e.getMessage(), e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }

    /**
     * 验证上传的文件
     * @param file 上传的文件
     */
    private void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }

        // 检查文件大小
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new IllegalArgumentException("文件大小不能超过5MB");
        }

        // 检查文件类型
        String contentType = file.getContentType();
        if (contentType == null || !ALLOWED_IMAGE_TYPES.contains(contentType.toLowerCase())) {
            throw new IllegalArgumentException("只支持图片文件格式：JPEG, PNG, GIF, WebP, BMP");
        }

        // 检查文件扩展名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || !hasValidImageExtension(originalFilename)) {
            throw new IllegalArgumentException("文件扩展名不正确");
        }
    }

    /**
     * 检查文件扩展名是否为有效的图片格式
     * @param filename 文件名
     * @return 是否为有效的图片扩展名
     */
    private boolean hasValidImageExtension(String filename) {
        String extension = getFileExtension(filename).toLowerCase();
        return Arrays.asList("jpg", "jpeg", "png", "gif", "webp", "bmp").contains(extension);
    }

    /**
     * 获取文件扩展名
     * @param filename 文件名
     * @return 文件扩展名
     */
    private String getFileExtension(String filename) {
        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex == -1) {
            return "";
        }
        return filename.substring(lastDotIndex + 1);
    }

    /**
     * 生成唯一的文件名
     * @param originalFilename 原始文件名
     * @return 唯一文件名
     */
    private String generateUniqueFileName(String originalFilename) {
        String extension = getFileExtension(originalFilename);
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
        String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
        return timestamp + "_" + uuid + "." + extension;
    }

    /**
     * 确保存储桶存在
     */
    private void ensureBucketExists() throws Exception {
        try {
            boolean bucketExists = minioClient.bucketExists(
                    BucketExistsArgs.builder().bucket(bucketName).build()
            );

            if (!bucketExists) {
                // 创建存储桶
                minioClient.makeBucket(
                        MakeBucketArgs.builder().bucket(bucketName).build()
                );

                // 设置存储桶策略为公开读取
                String policy = """
                        {
                            "Version": "2012-10-17",
                            "Statement": [
                                {
                                    "Effect": "Allow",
                                    "Principal": "*",
                                    "Action": "s3:GetObject",
                                    "Resource": "arn:aws:s3:::%s/*"
                                }
                            ]
                        }
                        """.formatted(bucketName);

                minioClient.setBucketPolicy(
                        SetBucketPolicyArgs.builder()
                                .bucket(bucketName)
                                .config(policy)
                                .build()
                );

                log.info("存储桶创建成功: {}", bucketName);
            }
        } catch (Exception e) {
            log.error("检查或创建存储桶失败: {}", e.getMessage(), e);
            throw new RuntimeException("存储桶操作失败: " + e.getMessage());
        }
    }

    /**
     * 生成文件访问URL
     * @param objectName 对象名
     * @return 文件访问URL
     */
    private String generateFileUrl(String objectName) {
        // 对于公开读取的存储桶，可以直接构建URL
        return endpoint + "/" + bucketName + "/" + objectName;
    }

    /**
     * 删除文件
     * @param objectName 对象名
     */
    public void deleteFile(String objectName) throws Exception {
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build()
            );
            log.info("文件删除成功: {}", objectName);
        } catch (Exception e) {
            log.error("文件删除失败: {}", e.getMessage(), e);
            throw new RuntimeException("文件删除失败: " + e.getMessage());
        }
    }
}
